#include<queue>
#include<pthread.h>
#include<unistd.h>
#include<iostream>
using namespace std;

const int default_thread_cap = 3;
const int default_task_cap = 3;

template<typename T>
class ThreadPool
{
public:
  ThreadPool(int task_num = default_task_cap,int thread_num = default_thread_cap) 
    :_thread_num(thread_num),_task_num(task_num),_exit(false)
  {
    pthread_mutex_init(&_mtx,nullptr);
    pthread_cond_init(&_c_cond,nullptr);
    pthread_cond_init(&_p_cond,nullptr);
    InitThreadPool();
  }
  ~ThreadPool()
  {
    pthread_mutex_destroy(&_mtx);
    pthread_cond_destroy(&_c_cond);
    pthread_cond_destroy(&_p_cond);
    ExitThreadPool();
  }
  void push(T task)
  {
    pthread_mutex_lock(&_mtx);
    if(_exit)
    {
      pthread_mutex_unlock(&_mtx);
      cout <<"处理任务的线程已经退出......" << endl;
      return ;
    }
    while(_task_queue.size() >= _task_num)
    {
      pthread_cond_wait(&_p_cond,&_mtx);
    }
    _task_queue.push(task);
    pthread_mutex_unlock(&_mtx);
    pthread_cond_signal(&_c_cond);
  }
  void pop(T* task)
  {
    *task = _task_queue.front();
    _task_queue.pop();
  }
  void ExitThreadPool()
  {
    _exit = true;
    while(_thread_num > 0)
      pthread_cond_signal(&_c_cond);
  }
  static void* Routine(void* arg)
  {
    ThreadPool<T>* tp = static_cast<ThreadPool<T>*>(arg);
    while(1)
    {
      pthread_mutex_lock(&tp->_mtx);
      while(tp->_task_queue.empty())
      {
        if(tp->_exit)
        {
          pthread_mutex_unlock(&tp->_mtx);
          cout << "thread: " << pthread_self() <<" exit ...." << endl;
          pthread_exit(nullptr);
        }
        pthread_cond_wait(&tp->_c_cond,&tp->_mtx);
      }
      T task;
      tp->pop(&task);
      pthread_mutex_unlock(&tp->_mtx);
      task();
    }
  }
  int InitThreadPool()
  {
    int thread_exit_num = 0;
    for(int i = 0;i<_thread_num;i++)
    {
      pthread_t tid;
      pthread_create(&tid,nullptr,Routine,this);
      if(tid < 0) thread_exit_num ++;
    }
    _thread_num -= thread_exit_num;
    return _thread_num;
  }
private:
  queue<T> _task_queue;
  pthread_mutex_t _mtx;
  pthread_cond_t _c_cond;
  pthread_cond_t _p_cond;
  int _thread_num;
  int _task_num;
  bool _exit;
};
